package cn.itcast.nems.oldems.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.nems.base.dao.entity.E2Clazz;
import cn.itcast.nems.base.dao.mapper.E2ClazzMapper;
import cn.itcast.nems.common.BasePageRequest;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.employee.dao.bean.EmployeeGroupBean;
import cn.itcast.nems.employee.dao.bean.EmployeeGroupsBean;
import cn.itcast.nems.manager.msas.MsasManager;
import cn.itcast.nems.manager.util.CustomBeanUtil;
import cn.itcast.nems.oldems.dao.dataobject.ContractInfoDO;
import cn.itcast.nems.oldems.dao.dataobject.StudentBelongerDO;
import cn.itcast.nems.oldems.dao.dataobject.StudentClazzInfoDO;
import cn.itcast.nems.oldems.dao.dataobject.StudentInfoDO;
import cn.itcast.nems.oldems.dao.entiry.Student;
import cn.itcast.nems.oldems.dao.entiry.StudentEditRecord;
import cn.itcast.nems.oldems.dao.entiry.StudentExtend;
import cn.itcast.nems.oldems.dao.entiry.StudentMergeLog;
import cn.itcast.nems.oldems.dao.mapper.StudentEditRecordMapper;
import cn.itcast.nems.oldems.dao.mapper.StudentExtendMapper;
import cn.itcast.nems.oldems.dao.mapper.StudentMapper;
import cn.itcast.nems.oldems.dao.mapper.StudentMergeLogMapper;
import cn.itcast.nems.oldems.dao.query.StudentDataQuery;
import cn.itcast.nems.oldems.dto.*;
import cn.itcast.nems.oldems.service.StudentContactService;
import cn.itcast.nems.oldems.service.StudentService;
import cn.itcast.nems.oldems.service.sync.OldEmsSyncService;
import cn.itcast.nems.order.dao.dataobject.OrderRefundDO;
import cn.itcast.nems.student.enumeration.StudentErrorBodyEnum;
import cn.itcast.nems.studentrecord.api.StudentRecordApi;
import cn.itcast.nems.studentrecord.constant.GenderEnum;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordStudentRelationship;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordMapper;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordStudentRelationshipMapper;
import cn.itcast.nems.studentrecord.dto.StudentRecordDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.itcast.nems.common.util.StreamUtils.distinctByKey;

@Service
@RequiredArgsConstructor
@Slf4j
public class StudentServiceImpl implements StudentService {

    private final StudentMapper studentMapper;
    private final StudentExtendMapper studentExtendMapper;
    private final StudentEditRecordMapper studentEditRecordMapper;
    private final E2ClazzMapper e2ClazzMapper;
    private final MsasManager manager;
    private final StudentRecordApi studentRecordApi;
    private final StudentRecordMapper studentRecordMapper;
    private final StudentRecordStudentRelationshipMapper studentRecordStudentRelationshipMapper;
    private final StudentContactService contactService;

    @Override
    public List<StudentBelongerDTO> queryStudentBelongerByIds(Set<Integer> studentIds) {
        List<StudentBelongerDO> list = studentMapper.queryStudentBelongerByIds(studentIds);
        return CollectionUtils.isEmpty(list) ? null :
                list.stream()
                        .map(item -> CustomBeanUtil.copyProperties(item, new StudentBelongerDTO()))
                        .toList();
    }

    @Override
    public List<StudentClazzInfoDTO> queryClazzListByStudentNos(Set<String> studentNos) {
        List<StudentClazzInfoDO> list = studentMapper.queryClazzListByStudentNos(studentNos);
        return CollectionUtils.isEmpty(list) ? null : list.stream().map(this::conveterToStudentClazzInfoDTO).toList();
    }

    private StudentClazzInfoDTO conveterToStudentClazzInfoDTO(StudentClazzInfoDO studentClazzInfoDO) {
        StudentClazzInfoDTO studentClazzInfoDTO = CustomBeanUtil.copyProperties(studentClazzInfoDO, new StudentClazzInfoDTO());
        return studentClazzInfoDTO;
    }

    @Override
    public List<StudentInfoDTO> queryStudentListByIds(Set<Integer> studentIds, String keyword) {
        List<StudentInfoDO> list = studentMapper.queryStudentListByIds(studentIds, keyword);
        return CollectionUtils.isEmpty(list) ? null :
                list.stream().map(this::convertToStudentInfoDTO).toList();
    }

    private StudentInfoDTO convertToStudentInfoDTO(StudentInfoDO studentInfoDO) {
        StudentInfoDTO studentInfoDTO = CustomBeanUtil.copyProperties(studentInfoDO, new StudentInfoDTO());
        if (StringUtils.hasText(studentInfoDTO.getGenderCode())) {
            studentInfoDTO.setGender(GenderEnum.valueOf(studentInfoDTO.getGenderCode()).getName());
        }
        return studentInfoDTO;
    }

    @Override
    public List<ContractInfoDTO> findListByStudentIds(Set<Integer> studentIds) {
        List<ContractInfoDO> list = studentMapper.findListByStudentIds(studentIds);
        return CollectionUtils.isEmpty(list) ? null :
                list.stream()
                        .map(item -> CustomBeanUtil.copyProperties(item, new ContractInfoDTO()))
                        .toList();
    }

    @Override
    public StudentBasicInfoDto studentInfoById(Integer studentId) {
        Student student = studentMapper.selectById(studentId);
        if (student == null) {
            BizExceptionProducer.throwProduce(StudentErrorBodyEnum.STUDENT_NOT_FOUND);
        }
        StudentExtend studentExtend = studentExtendMapper.selectById(studentId);
        if (studentExtend == null) {
            studentExtend = new StudentExtend();
        }
        boolean hasAcademyCoupon = studentMapper.countAcademyCoupon(studentId) > 0;
        String currentClassName = null;
        if (student.getClassId() != null) {
            var clazz = e2ClazzMapper.selectOne(new QueryWrapper<E2Clazz>().lambda().eq(E2Clazz::getClazzId, student.getClassId()));
            if (clazz != null) {
                currentClassName = clazz.getClazzName();
            }
        }
        String pc = lastProveContent(studentId);
        //////////////
        StudentBasicInfoDto vo = new StudentBasicInfoDto();
        vo.setName(student.getName());
        vo.setGender(student.getGender());
        vo.setIdcard(DesensitizedUtil.idCardNum(student.getIdcard(), 2, 2));
        vo.setBrithday(student.getBirthday());
        vo.setPhone(DesensitizedUtil.mobilePhone(student.getPhone()));
        vo.setEducation(student.getEducation());
        vo.setNumber(student.getNumber());
        vo.setId(student.getId());
        vo.setCurrentClassName(currentClassName);
        vo.setJobIntention(studentExtend.getJobIntention());
        vo.setFromcolleges(student.getFromcolleges());
        vo.setAcademyCoupon(hasAcademyCoupon);
        vo.setCurrentStatus(studentExtend.getCurrentStatus());
        vo.setProveTraining(pc.contains("培训"));
        vo.setProvePractice(pc.contains("实习"));
        vo.setSchedulehostel(student.getSchedulehostel());
        vo.setTeacher(student.getTeacher());
        vo.setComment(student.getComment());
        vo.setMerged(student.getMerged());
        vo.setMergeable(mergeable(student));
        setMergeTo(vo);
        return vo;
    }

    private final StudentMergeLogMapper studentMergeLogMapper;

    private void setMergeTo(StudentBasicInfoDto vo) {
        if (vo.getMerged()) {
            var list = studentMergeLogMapper.selectList(new QueryWrapper<StudentMergeLog>()
                    .lambda()
                    .eq(StudentMergeLog::getFromStudentId, vo.getId()));
            if (list.isEmpty()) {
                return;
            }
            var model = list.stream().findFirst().get();
            vo.setMergeToStudentId(model.getToStudentId());
        }
    }

    private boolean mergeable(Student student) {
        if (student.getMerged()) return false;
        return studentMapper.selectCount(new QueryWrapper<Student>()
                .lambda()
                .ne(Student::getId, student.getId())
                .eq(Student::getName, student.getName())
                .eq(Student::getMerged, Boolean.FALSE)
        ) > 0;
    }

    @Override
    public List<StudentListDto> mergeToList(int studentId) {
        var student = studentMapper.selectById(studentId);
        Assert.notNull(student, "学员未找到");
        var list = studentMapper.selectList(new QueryWrapper<Student>()
                .lambda()
                .ne(Student::getId, student.getId())
                .eq(Student::getName, student.getName())
                .eq(Student::getMerged, Boolean.FALSE)
        );
        var result = list.stream().map(this::mergeToVo).toList();
        setEmail(result);
        return result;
    }

    private StudentListDto mergeToVo(Student student) {
        StudentListDto dto = CustomBeanUtil.copyProperties(student, new StudentListDto());
        return dto;
    }

    private void setEmail(List<StudentListDto> result) {
        var studentIdList = result.stream().map(StudentListDto::getId).toList();
        var map = contactService.mapContact(studentIdList, "EMAIL");
        for (StudentListDto studentListDto : result) {
            studentListDto.setEmail(map.get(studentListDto.getId()));
        }
    }

    private String lastProveContent(Integer studentId) {
        // prov 是否开具了培训、实习等证明
        StudentEditRecord record = new StudentEditRecord();
        record.setStudentId(studentId);
        record.setType(StudentEditRecord.TYPE_PROVE);
        record = studentEditRecordMapper.selectOne(
                new QueryWrapper<>(record)
                        .lambda()
                        .orderByDesc(StudentEditRecord::getEditDate)
                        .last("limit 1")
        );
        if (record != null) {
            if (StringUtils.hasText(record.getContent())) {
                return record.getContent();
            }
        }
        return "";
    }

    @Override
    public StudentDto findByStudentOrderId(String studentOrderId) {
        final Student student = this.studentMapper.findByOrderId(studentOrderId);
        StudentDto dto = new StudentDto();
        BeanUtils.copyProperties(student, dto);
        return dto;
    }

    @Override
    public StudentDto findById(Integer studentId) {
        Student student = studentMapper.selectById(studentId);
        if (student == null) {
            BizExceptionProducer.throwProduce(StudentErrorBodyEnum.STUDENT_NOT_FOUND);
        }
        var dto = new StudentDto();
        dto.setId(student.getId());
        dto.setName(student.getName());
        dto.setSimplespell(student.getSimplespell());
        dto.setGender(student.getGender());
        dto.setPhone(student.getPhone());
        dto.setEmail(student.getEmail());
        dto.setQqnumber(student.getQqnumber());
        dto.setIdcard(student.getIdcard());
        dto.setBirthday(student.getBirthday());
        dto.setEducation(student.getEducation());
        dto.setProfession(student.getProfession());
        dto.setSchool(student.getSchool());
        dto.setImagepath(student.getImagepath());
        dto.setContry(student.getContry());
        dto.setProvinceId(student.getProvinceId());
        dto.setAddress(student.getAddress());
        dto.setCurrentaddress(student.getCurrentaddress());
        dto.setHomephone(student.getHomephone());
        dto.setHomecontact(student.getHomecontact());
        dto.setSchedulehostel(student.getSchedulehostel());
        dto.setFromcolleges(student.getFromcolleges());
        dto.setInfoorigin(student.getInfoorigin());
        dto.setComeschooltime(student.getComeschooltime());
        dto.setCreatetime(student.getCreatetime());
        dto.setEmployeeId(student.getEmployeeId());
        dto.setComment(student.getComment());
        dto.setTeacher(student.getTeacher());
        dto.setProve(student.getProve());
        dto.setClassId(student.getClassId());
        dto.setLuckdrawStatus(student.getLuckdrawStatus());
        dto.setContractNumber(student.getContractNumber());
        dto.setNumber(student.getNumber());
        dto.setStatus(student.getStatus());
        dto.setGid(student.getGid());
        dto.setLastUpdateTime(student.getLastUpdateTime());
        dto.setAccountId(student.getAccountId());
        dto.setMerged(student.getMerged());
        return dto;
    }

    @Override
    public int setStudentCurrentAddress(Integer id, String currentAddress) {
        return studentMapper.update(
                null,
                new UpdateWrapper<Student>()
                        .lambda()
                        .eq(Student::getId, id)
                        .set(Student::getCurrentaddress, currentAddress)
        );
    }

    @Override
    public Page<StudentListDto> page(@NonNull BasePageRequest<StudentDataQueryDto> pageRequest) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<OrderRefundDO> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>();
        page.setCurrent(pageRequest.getPageNumber());
        page.setSize(pageRequest.getPageSize());
        StudentDataQueryDto query = pageRequest.getCondition();
        EmployeeGroupsBean groups = null;
//        if (query.getExcludeFlag() != null && query.getExcludeFlag()) {
//            groups = AccountHolder.getRequiredAccountEmployeeGroups();
//            if (groups.getGroupList().isEmpty()) {
//                return Page.of(1, pageRequest.getPageSize(), 0, new ArrayList<>());
//            }
//        }

        IPage<Student> data = studentMapper.findPageData(page, dtoToQuery(query, groups));
        return Page.of(
                Long.valueOf(data.getCurrent()).intValue(),
                Long.valueOf(data.getSize()).intValue(),
                Long.valueOf(data.getTotal()).intValue(),
                mapToVo(data.getRecords(), query, groups)
        );
    }

    @Override
    public List<StudentListDto> list(StudentDataQueryDto query) {
        return mapToVo(studentMapper.findPageData(dtoToQuery(query, null)), query, null);
    }

    @Override
    @Transactional
    public Boolean update(StudentBasicInfoDto vo) {
        String employeeName = null;
        try {
            employeeName = manager.getAccount(AccountHolder.getRequiredAccount()).getName();
        } catch (Exception e) {
            log.error("获取员工信息失败", e);
        }
        var student = studentMapper.selectById(vo.getId());
        studentMapper.update(
                null,
                new UpdateWrapper<Student>()
                        .lambda()
                        .eq(Student::getId, vo.getId())
                        .set(Student::getName, vo.getName())
                        .set(Student::getGender, vo.getGender())
                        .set(Student::getIdcard, vo.getIdcard())
                        .set(Student::getBirthday, vo.getBrithday())
                        .set(Student::getEducation, vo.getEducation())
                        .set(Student::getFromcolleges, vo.getFromcolleges())
                        .set(Student::getSchedulehostel, vo.getSchedulehostel())
                        .set(Student::getTeacher, vo.getTeacher())
                        .set(Student::getComment, vo.getComment())
                        .set(Student::getProve, vo.getProveTraining() || vo.getProvePractice())
        );
        if (
            // comment 在数据中是nullable字段
                !Objects.equals(vo.getComment(), student.getComment())
        ) {
            var record = new StudentEditRecord();
            record.setStudentId(vo.getId());
            record.setType(StudentEditRecord.TYPE_COMMENT);
            record.setContent(vo.getComment());
            record.setEditDate(LocalDateTime.now());
            record.setUsername(AccountHolder.getRequiredAccount());
            record.setRealname(employeeName);
            studentEditRecordMapper.insert(record);
        }
        if (studentExtendMapper.selectById(vo.getId()) != null) {
            studentExtendMapper.update(
                    null,
                    new UpdateWrapper<StudentExtend>()
                            .lambda()
                            .eq(StudentExtend::getId, vo.getId())
                            .set(StudentExtend::getJobIntention, vo.getJobIntention())
                            .set(StudentExtend::getCurrentStatus, vo.getCurrentStatus())
            );
        } else {
            StudentExtend studentExtend = new StudentExtend();
            studentExtend.setId(vo.getId());
            studentExtend.setJobIntention(vo.getJobIntention());
            studentExtend.setCurrentStatus(vo.getCurrentStatus());
            studentExtendMapper.insert(studentExtend);
        }
        if (vo.getAcademyCoupon()) {
            if (!vo.getFromcolleges()) {
                BizExceptionProducer.throwProduce(StudentErrorBodyEnum.NOT_COLLAGE);
            }
            if (!(studentMapper.countAcademyCoupon(vo.getId()) > 0)) {
                studentMapper.saveAcademyCoupon(
                        vo.getId(),
                        true,
                        new Date()
                );
            }
        } else {
            if (studentMapper.countAcademyCoupon(vo.getId()) > 0) {
                studentMapper.deleteAcademyCouponByStudentId(vo.getId());
            }
        }


        // prov 是否开具了培训、实习等证明
        String rc = "";
        StudentEditRecord record = new StudentEditRecord();
        record.setStudentId(vo.getId());
        record.setType(StudentEditRecord.TYPE_PROVE);
        record = studentEditRecordMapper.selectOne(
                new QueryWrapper<>(record)
                        .lambda()
                        .orderByDesc(StudentEditRecord::getEditDate)
                        .last("limit 1")
        );
        if (record != null) {
            if (StringUtils.hasText(record.getContent())) {
                rc = record.getContent();
            }
        }
        boolean srcProveTraining = rc.contains("培训");
        boolean srcProvePractice = rc.contains("实习");
        if (vo.getProveTraining() != srcProveTraining || vo.getProvePractice() != srcProvePractice) {
            // 培训证明
            // 实习证明
            String content = "";
            if (vo.getProveTraining()) {
                content += "培训证明";
            }
            if (vo.getProvePractice()) {
                if (StringUtils.hasText(content)) {
                    content += ",";
                }
                content += "实习等证明";
            }
            record = new StudentEditRecord();
            record.setStudentId(vo.getId());
            record.setType(StudentEditRecord.TYPE_PROVE);
            record.setContent(content);
            record.setEditDate(LocalDateTime.now());
            record.setUsername(AccountHolder.getRequiredAccount());
            record.setRealname(employeeName);
            studentEditRecordMapper.insert(record);
        }
        return true;
    }

    @Override
    public List<ContractInfoDTO> findContractClazzByStudentIdAndClazzId(@NotNull Integer studentId, Integer clazzId,String contractNumber) {
        List<ContractInfoDO> contractInfoList = studentMapper.findContractInfoByStudentIdAndClazzId(studentId, clazzId ,contractNumber);
        return CollectionUtils.isEmpty(contractInfoList) ? null :
                contractInfoList.stream()
                        .map(item -> CustomBeanUtil.copyProperties(item, new ContractInfoDTO()))
                        .toList();
    }

    public List<ContractInfoDTO> findClassContractInfoByStudentId(@NotNull Integer studentId) {
        List<ContractInfoDO> contractInfoList = studentMapper.findClassContractInfoByStudentId(studentId);
        return CollectionUtils.isEmpty(contractInfoList) ? null :
                contractInfoList.stream()
                        .map(item -> CustomBeanUtil.copyProperties(item, new ContractInfoDTO()))
                        .toList();
    }


    private StudentDataQuery dtoToQuery(StudentDataQueryDto dto, EmployeeGroupsBean groups) {
        var query = new StudentDataQuery();
        query.setName(dto.getName());
        query.setGender(dto.getGender());
        query.setNumber(dto.getNumber());
        query.setId(dto.getId());
        query.setPhone(dto.getPhone());
        query.setIdcard(dto.getIdcard());
        query.setQqnumber(dto.getQqnumber());
        query.setComeschooltime(dto.getComeschooltime());
        query.setComeschooltimestart(dto.getComeschooltimestart());
        query.setComeschooltimeend(dto.getComeschooltimeend());
        query.setClassId(dto.getClassId());
        query.setClassName(dto.getClassName());
        query.setModelId(dto.getModelId());
        query.setSubjectId(dto.getSubjectId());
        query.setIds(dto.getIds());
        query.setLockFlag(dto.getLockFlag());
        query.setKeyword(dto.getKeyword());
        if (groups != null) {
            query.setExcludeFlag(dto.getExcludeFlag());
            query.setEmployeeGroups(groups.getGroupList());
        }
        return query;
    }

    private List<StudentListDto> mapToVo(List<Student> records, StudentDataQueryDto query, EmployeeGroupsBean groups) {
        if (records == null) {
            return null;
        }
        if (records.isEmpty()) {
            return new ArrayList<>();
        }
        Set<Integer> studentIdSet = records.stream().map(Student::getId).collect(Collectors.toSet());
        String state = query.getState();
        List<StudentRecordDTO> studentRecordDTOList = this.studentRecordApi.queryByStudentIds(studentIdSet, state);
        if (CollectionUtil.isEmpty(studentRecordDTOList)) {
            studentRecordDTOList = new ArrayList<>();
        }
        Set<Integer> clazzIdSet = Stream.of(
                records.stream().map(Student::getClassId),
                studentRecordDTOList.stream().map(StudentRecordDTO::getClazzId)
        ).flatMap(i -> i).collect(java.util.stream.Collectors.toSet());
        Map<Integer, E2Clazz> clazzMap;
        if (clazzIdSet.isEmpty()) {
            clazzMap = new HashMap<>();
        } else {
            clazzMap = e2ClazzMapper.selectList(new QueryWrapper<E2Clazz>().lambda().in(E2Clazz::getClazzId, clazzIdSet)).stream()
                    .collect(Collectors.toMap(E2Clazz::getClazzId, o -> o));
        }
        Map<Integer, List<StudentRecordDTO>> studentRecordMap = studentRecordDTOList.stream()
                .filter(o -> null == query.getLockFlag() || query.getLockFlag().equals(o.getLockFlag()))
                .filter(o -> {
                    if (query.getClazzFilterCanTransfer() != null && query.getClazzFilterCanTransfer()) {
                        var clazz = clazzMap.get(o.getClazzId());
                        if (clazz == null) {
                            return false;
                        }
                        return
                                // 学籍有效
                                "VALID".equals(o.getState())
                                        // 不能已出班
                                        && o.getSettlementDate() == null
                                        // 不能是休学班
                                        && !clazz.getSuspensionFlag()
                                        // 不能是待定班
                                        && !clazz.getDelayFlag()
                                        // 不能是结课班级
                                        && (clazz.getGraduationDate() == null || clazz.getGraduationDate().isAfter(LocalDate.now()))
                                ;
                    }
                    return true;
                })
                .filter(o -> {
                    if (query.getClazzFilterCanDropout() != null && query.getClazzFilterCanDropout()) {
                        return o.getSettlementDate() == null;
                    }
                    return true;
                })
                .collect(Collectors.groupingBy(StudentRecordDTO::getStudentId));
        var clazzNameMap = clazzMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, o -> o.getValue().getClazzName()));
        List<StudentListDto> result = new ArrayList<>(records.size());
        for (Student record : records) {
            StudentListDto vo = new StudentListDto();
            vo.setId(record.getId());
            vo.setName(record.getName());
            vo.setGender(record.getGender());
            vo.setNumber(record.getNumber());
            vo.setPhone(DesensitizedUtil.mobilePhone(record.getPhone()));
            vo.setIdcard(DesensitizedUtil.idCardNum(record.getIdcard(), 2, 2));
            vo.setQqnumber(record.getQqnumber());
            vo.setCurrentClassName(clazzNameMap.get(record.getClassId()));
            vo.setStudentRecordDTOList(studentRecordMap.get(record.getId()));
            vo.setMerged(record.getMerged());
            result.add(vo);
        }
        // 把没用的学籍删掉不显示
        if (groups == null) {
            return result;
        }
        for (StudentListDto studentListDto : result) {
            if (groups.getGroupList().isEmpty()) {
                studentListDto.setStudentRecordDTOList(null);
            }
            var recordDTOList = studentListDto.getStudentRecordDTOList();
            if (recordDTOList == null) {
                continue;
            }
            var newList = new ArrayList<StudentRecordDTO>();
            R:
            for (StudentRecordDTO studentRecordDTO : recordDTOList) {
                var clazz = clazzMap.get(studentRecordDTO.getClazzId());
                if (clazz == null) {
                    continue;
                }
                for (EmployeeGroupBean employeeGroupBean : groups.getGroupList()) {
                    if (employeeGroupBean.getSchoolCodeList().contains(clazz.getSchoolCode()) && employeeGroupBean.getSubjectIdList().contains(clazz.getSubjectId())) {
                        studentRecordDTO.setSubjectId(clazz.getSubjectId());
                        studentRecordDTO.setSubjectName(clazz.getSubjectName());
                        studentRecordDTO.setSchoolId(clazz.getSchoolCode());
                        studentRecordDTO.setSchoolName(clazz.getSchoolName());
                        newList.add(studentRecordDTO);
                        continue R;
                    }
                }
            }
            studentListDto.setStudentRecordDTOList(newList);
        }
        return result;
    }

    @Override
    @Transactional
    public Boolean merge(Integer fromStudentId, Integer toStudentId) {
        var fromStudent = studentMapper.selectById(fromStudentId);
        Assert.notNull(fromStudent, "原学生没有找到");
        var toStudent = studentMapper.selectById(toStudentId);
        Assert.notNull(toStudent, "目标学生没有找到");
        Assert.isTrue(!fromStudent.getMerged(), "原学生已经被合并过");
        Assert.isTrue(fromStudent.getName().equals(toStudent.getName()), "姓名一致的学院才能够被合并");
        assetCanMerge(fromStudentId, toStudentId);
        moveRelationship(fromStudentId, toStudentId);
//        markStudentMerged(fromStudentId);
//        setIdCard(toStudent.getId(), fromStudent.getIdcard());
        oldEmsSyncService.mergeStudent(
                fromStudentId,
                toStudentId,
                MergeStudentReason.NAME,
                AccountHolder.getRequiredAccountInfo().getEmail()
        );
        return Boolean.TRUE;
    }

    private final OldEmsSyncService oldEmsSyncService;

    private void assetCanMerge(Integer fromStudentId, Integer toStudentId) {
        // todo 检查学籍有没有冲突
        var list = studentRecordApi.queryByStudentIds(Set.of(fromStudentId, toStudentId), null);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        var size1 = list.size();
        var size2 = list.stream().filter(distinctByKey(StudentRecordDTO::getClazzId)).count();
        Assert.isTrue(size1 == size2, "学员有相同班级，不能合并");
    }

    private void markStudentMerged(Integer fromStudentId) {
        studentMapper.update(
                null,
                new UpdateWrapper<Student>(null)
                        .lambda()
                        .eq(Student::getId, fromStudentId)
                        .set(Student::getMerged, Boolean.TRUE)
        );
    }

    private void moveRelationship(Integer fromStudentId, Integer toStudentId) {
        studentRecordStudentRelationshipMapper.update(
                null,
                new UpdateWrapper<StudentRecordStudentRelationship>(null)
                        .lambda()
                        .eq(StudentRecordStudentRelationship::getStudentId, fromStudentId)
                        .set(StudentRecordStudentRelationship::getStudentId, toStudentId)
                        .set(StudentRecordStudentRelationship::getModifiedBy, AccountHolder.getRequiredAccountInfo().getEmail())
                        .set(StudentRecordStudentRelationship::getModifiedDatetime, LocalDateTime.now())
        );
    }

    private void setIdCard(Integer id, String idcard) {
        if (StringUtils.hasText(idcard))
            studentMapper.update(
                    null,
                    new UpdateWrapper<Student>()
                            .lambda()
                            .eq(Student::getId, id)
                            .set(Student::getIdcard, idcard)
            );
    }
}

